Conditions | 59 |
Total Lines | 391 |
Code Lines | 199 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like egw_action_dragdrop.js ➔ egwDragActionImplementation often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | /** |
||
76 | function egwDragActionImplementation() |
||
77 | { |
||
78 | var ai = new egwActionImplementation(); |
||
79 | |||
80 | ai.type = "drag"; |
||
81 | |||
82 | ai.helper = null; |
||
83 | ai.ddTypes = []; |
||
84 | ai.selected = []; |
||
85 | |||
86 | // Define default helper DOM |
||
87 | // default helper also can be called later in application code in order to customization |
||
88 | ai.defaultDDHelper = function (_selected) |
||
89 | { |
||
90 | // Table containing clone of rows |
||
91 | var table = jQuery(document.createElement("table")).addClass('egwGridView_grid et2_egw_action_ddHelper_row'); |
||
92 | // tr element to use as last row to show lable more ... |
||
93 | var moreRow = jQuery(document.createElement('tr')).addClass('et2_egw_action_ddHelper_moreRow'); |
||
94 | // Main div helper container |
||
95 | var div = jQuery(document.createElement("div")).append(table); |
||
96 | |||
97 | var rows = []; |
||
98 | // Maximum number of rows to show |
||
99 | var maxRows = 3; |
||
100 | // item label |
||
101 | var itemLabel = egw.lang(egw.link_get_registry(egw.app_name(),_selected.length > 1?'entries':'entry')||egw.app_name()); |
||
102 | |||
103 | var index = 0; |
||
104 | |||
105 | // Take select all into account when counting number of rows, because they may not be |
||
106 | // in _selected object |
||
107 | var pseudoNumRows = (_selected[0] && _selected[0]._context && _selected[0]._context._selectionMgr && |
||
108 | _selected[0]._context._selectionMgr._selectAll) ? |
||
109 | _selected[0]._context._selectionMgr._total : _selected.length; |
||
110 | |||
111 | for (var i = 0; i < _selected.length;i++) |
||
112 | { |
||
113 | var row = jQuery(_selected[i].iface.getDOMNode()).clone(); |
||
114 | if (row) |
||
115 | { |
||
116 | rows.push(row); |
||
117 | table.append(row); |
||
118 | } |
||
119 | index++; |
||
120 | if (index == maxRows) |
||
121 | { |
||
122 | // Lable to show number of items |
||
123 | var spanCnt = jQuery(document.createElement('span')) |
||
124 | .addClass('et2_egw_action_ddHelper_itemsCnt') |
||
125 | .appendTo(div); |
||
126 | |||
127 | spanCnt.text(pseudoNumRows +' '+ itemLabel); |
||
128 | // Number of not shown rows |
||
129 | var restRows = pseudoNumRows - maxRows; |
||
130 | if (restRows) |
||
131 | { |
||
132 | moreRow.text((pseudoNumRows - maxRows) +' '+egw.lang('more %1 selected ...', itemLabel)); |
||
133 | } |
||
134 | table.append(moreRow); |
||
135 | break; |
||
136 | } |
||
137 | } |
||
138 | |||
139 | var text = jQuery(document.createElement('div')).addClass('et2_egw_action_ddHelper_tip'); |
||
140 | div.append(text); |
||
141 | |||
142 | // Add notice of Ctrl key, if supported |
||
143 | if('draggable' in document.createElement('span') && |
||
144 | navigator && navigator.userAgent.indexOf('Chrome') >= 0 && egw.app_name() == 'filemanager') // currently only filemanager supports drag out |
||
145 | { |
||
146 | var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? |
||
147 | egw.lang('Alt') : egw.lang('Command ⌘'); |
||
148 | text.text(egw.lang('Hold [%1] and [%2] key to drag %3 to your desktop', key, egw.lang('Shift ⇧'), itemLabel)); |
||
149 | } |
||
150 | // Final html DOM return as helper structor |
||
151 | return div; |
||
152 | }; |
||
153 | |||
154 | ai.doRegisterAction = function(_aoi, _callback, _context) |
||
155 | { |
||
156 | var node = _aoi.getDOMNode(); |
||
157 | |||
158 | if (node) |
||
159 | { |
||
160 | // Prevent selection |
||
161 | node.onselectstart = function () { |
||
162 | return false; |
||
163 | }; |
||
164 | if (!(window.FileReader && 'draggable' in document.createElement('span')) ) |
||
165 | { |
||
166 | // No DnD support |
||
167 | return; |
||
|
|||
168 | } |
||
169 | |||
170 | // It shouldn't be so hard to get the action... |
||
171 | var action = null; |
||
172 | var groups = _context.getActionImplementationGroups(); |
||
173 | if(!groups.drag) return; |
||
174 | for(var i = 0; i < groups.drag.length; i++) |
||
175 | { |
||
176 | // dragType 'file' says it can be dragged as a file |
||
177 | if(groups.drag[i].link.actionObj.dragType == 'file' || groups.drag[i].link.actionObj.dragType.indexOf('file') > -1) |
||
178 | { |
||
179 | action = groups.drag[i].link.actionObj; |
||
180 | break; |
||
181 | } |
||
182 | } |
||
183 | if(action) |
||
184 | { |
||
185 | /** |
||
186 | * We found an action with dragType 'file', so by holding Ctrl |
||
187 | * key & dragging, user can drag from browser to system. |
||
188 | * The global data store must provide a full, absolute URL in 'download_url' |
||
189 | * and a mime in 'mime'. |
||
190 | * |
||
191 | * Unfortunately, Native DnD to drag the file conflicts with jQueryUI draggable, |
||
192 | * which handles all the other DnD actions. We get around this by: |
||
193 | * 1. Require the user indicate a file drag with Ctrl key |
||
194 | * 2. Disable jQueryUI draggable, then turn on native draggable attribute |
||
195 | * This way we can at least toggle which one is operating, so they |
||
196 | * both work alternately if not together. |
||
197 | */ |
||
198 | // Native DnD - Doesn't play nice with jQueryUI Sortable |
||
199 | // Tell jQuery to include this property |
||
200 | jQuery.event.props.push('dataTransfer'); |
||
201 | |||
202 | jQuery(node).off("mousedown") |
||
203 | .on("mousedown", function(event) { |
||
204 | var dragOut = _context.isDragOut(event); |
||
205 | jQuery(this).attr("draggable", dragOut? "true" : ""); |
||
206 | jQuery(node).draggable("option","disabled",dragOut); |
||
207 | if (dragOut) |
||
208 | { |
||
209 | // Disabling draggable adds some UI classes, but we don't care so remove them |
||
210 | jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled"); |
||
211 | |||
212 | } |
||
213 | else |
||
214 | { |
||
215 | if (_context.isSelection(event)) |
||
216 | { |
||
217 | jQuery(node).draggable("disable"); |
||
218 | // Disabling draggable adds some UI classes, but we don't care so remove them |
||
219 | jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled"); |
||
220 | } |
||
221 | else if(event.which != 3) |
||
222 | { |
||
223 | document.getSelection().removeAllRanges(); |
||
224 | } |
||
225 | if(!(dragOut) || !this.addEventListener) return; |
||
226 | } |
||
227 | }) |
||
228 | .on ("mouseup", function (event){ |
||
229 | if (_context.isSelection(event)) |
||
230 | jQuery(node).draggable("enable"); |
||
231 | }) |
||
232 | .on("dragstart", function(event) { |
||
233 | if(_context.isSelection(event)) return; |
||
234 | if(event.dataTransfer == null) { |
||
235 | return; |
||
236 | } |
||
237 | event.dataTransfer.effectAllowed="copy"; |
||
238 | |||
239 | // Get all selected |
||
240 | // Multiples aren't supported by event.dataTransfer, yet, so |
||
241 | // select only the row they clicked on. |
||
242 | // var selected = _context.getSelectedLinks('drag'); |
||
243 | var selected = [_context]; |
||
244 | _context.parent.setAllSelected(false); |
||
245 | _context.setSelected(true); |
||
246 | |||
247 | // Set file data |
||
248 | for(var i = 0; i < selected.length; i++) |
||
249 | { |
||
250 | var data = selected[i].data || egw.dataGetUIDdata(selected[i].id).data || {}; |
||
251 | if(data && data.mime && data.download_url) |
||
252 | { |
||
253 | var url = data.download_url; |
||
254 | |||
255 | // NEED an absolute URL |
||
256 | if (url[0] == '/') url = egw.link(url); |
||
257 | // egw.link adds the webserver, but that might not be an absolute URL - try again |
||
258 | if (url[0] == '/') url = window.location.origin+url; |
||
259 | |||
260 | // Unfortunately, dragging files is currently only supported by Chrome |
||
261 | if(navigator && navigator.userAgent.indexOf('Chrome')) |
||
262 | { |
||
263 | event.dataTransfer.setData("DownloadURL", data.mime+':'+data.name+':'+url); |
||
264 | } |
||
265 | else |
||
266 | { |
||
267 | // Include URL as a fallback |
||
268 | event.dataTransfer.setData("text/uri-list", url); |
||
269 | } |
||
270 | } |
||
271 | } |
||
272 | if(event.dataTransfer.types.length == 0) |
||
273 | { |
||
274 | // No file data? Abort: drag does nothing |
||
275 | event.preventDefault(); |
||
276 | return; |
||
277 | } |
||
278 | |||
279 | // Create drag icon |
||
280 | _callback.call(_context, _context, ai); |
||
281 | // Drag icon must be visible for setDragImage() - we'll remove it on drag |
||
282 | jQuery("body").append(ai.helper); |
||
283 | event.dataTransfer.setDragImage(ai.helper[0],-12,-12); |
||
284 | }) |
||
285 | .on("drag", function(e) { |
||
286 | // Remove the helper, it has been copied into the dataTransfer object now |
||
287 | // Hopefully user didn't notice it... |
||
288 | if(e.dataTransfer != null) |
||
289 | { |
||
290 | ai.helper.remove(); |
||
291 | } |
||
292 | }); |
||
293 | } |
||
294 | else |
||
295 | { |
||
296 | // Use Ctrl key in order to select content |
||
297 | jQuery(node).off("mousedown") |
||
298 | .on({ |
||
299 | mousedown: function(event){ |
||
300 | if (_context.isSelection(event)){ |
||
301 | jQuery(node).draggable("disable"); |
||
302 | // Disabling draggable adds some UI classes, but we don't care so remove them |
||
303 | jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled"); |
||
304 | } |
||
305 | else if(event.which != 3) |
||
306 | { |
||
307 | document.getSelection().removeAllRanges(); |
||
308 | } |
||
309 | }, |
||
310 | mouseup: function (){ |
||
311 | jQuery(node).draggable("enable"); |
||
312 | // Set cursor back to auto. Seems FF can't handle cursor reversion |
||
313 | jQuery('body').css({cursor:'auto'}); |
||
314 | } |
||
315 | }); |
||
316 | } |
||
317 | jQuery(node).draggable( |
||
318 | { |
||
319 | "distance": 20, |
||
320 | "cursor": "move", |
||
321 | "cursorAt": { top: -12, left: -12 }, |
||
322 | "helper": function(e) { |
||
323 | // The helper function is called before the start function |
||
324 | // is evoked. Call the given callback function. The callback |
||
325 | // function will gather the selected elements and action links |
||
326 | // and call the doExecuteImplementation function. This |
||
327 | // will call the onExecute function of the first action |
||
328 | // in order to obtain the helper object (stored in ai.helper) |
||
329 | // and the multiple dragDropTypes (ai.ddTypes) |
||
330 | _callback.call(_context, false, ai); |
||
331 | |||
332 | jQuery(node).data("ddTypes", ai.ddTypes); |
||
333 | jQuery(node).data("selected", ai.selected); |
||
334 | |||
335 | if (ai.helper) |
||
336 | { |
||
337 | // Add a basic class to the helper in order to standardize the background layout |
||
338 | ai.helper.addClass('et2_egw_action_ddHelper'); |
||
339 | |||
340 | // Append the helper object to the body element - this |
||
341 | // fixes a bug in IE: If the element isn't inserted into |
||
342 | // the DOM-tree jquery appends it to the parent node. |
||
343 | // In case this is a table it doesn't work correctly |
||
344 | jQuery("body").append(ai.helper); |
||
345 | return ai.helper; |
||
346 | } |
||
347 | |||
348 | // Return an empty div if the helper dom node is not set |
||
349 | return ai.defaultDDHelper(ai.selected);//jQuery(document.createElement("div")).addClass('et2_egw_action_ddHelper'); |
||
350 | }, |
||
351 | "start": function(e) { |
||
352 | return ai.helper != null; |
||
353 | }, |
||
354 | revert: function(valid) |
||
355 | { |
||
356 | var dTarget = this; |
||
357 | if (!valid) |
||
358 | { |
||
359 | // Tolerance value of pixels arround the draggable target |
||
360 | // to distinguish whether the action was intended for dragging or selecting content. |
||
361 | var tipTelorance = 10; |
||
362 | var helperTop = ai.helper.position().top; |
||
363 | |||
364 | if (helperTop >= dTarget.offset().top |
||
365 | && helperTop <= (dTarget.height() + dTarget.offset().top) + tipTelorance) |
||
366 | { |
||
367 | var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? |
||
368 | egw.lang("Ctrl") : egw.lang("Command ⌘"); |
||
369 | // We can not use Ctrl key for FF because FF has specific function |
||
370 | // for element selection bound to ctrl key and it would confilicts |
||
371 | // with our selection functionallity. Therefore, we use Alt key when |
||
372 | // it comes to FF regardless of OS. |
||
373 | if (window.navigator.userAgent.match(/firefox/i)) key = egw.lang("Alt"); |
||
374 | egw.message(egw.lang('Hold [%1] key to select text eg. to copy it', key), 'info'); |
||
375 | } |
||
376 | |||
377 | // Invalid target |
||
378 | return true; |
||
379 | } |
||
380 | else |
||
381 | { |
||
382 | // Valid target |
||
383 | return false; |
||
384 | } |
||
385 | }, |
||
386 | // Solves problem with scroll position changing in the grid |
||
387 | // component |
||
388 | "refreshPositions": true, |
||
389 | "scroll": false, |
||
390 | //"containment": "document", |
||
391 | "iframeFix": true, |
||
392 | "delay": 300 |
||
393 | } |
||
394 | ); |
||
395 | |||
396 | |||
397 | return true; |
||
398 | } |
||
399 | return false; |
||
400 | }; |
||
401 | |||
402 | ai.doUnregisterAction = function(_aoi) |
||
403 | { |
||
404 | var node = _aoi.getDOMNode(); |
||
405 | |||
406 | if (node && jQuery(node).data("uiDraggable")){ |
||
407 | jQuery(node).draggable("destroy"); |
||
408 | } |
||
409 | }; |
||
410 | |||
411 | /** |
||
412 | * Builds the context menu and shows it at the given position/DOM-Node. |
||
413 | * |
||
414 | * @param {string} _context |
||
415 | * @param {array} _selected |
||
416 | * @param {object} _links |
||
417 | */ |
||
418 | ai.doExecuteImplementation = function(_context, _selected, _links) |
||
419 | { |
||
420 | // Reset the helper object of the action implementation |
||
421 | this.helper = null; |
||
422 | var hasLink = false; |
||
423 | |||
424 | // Store the drag-drop types |
||
425 | this.ddTypes = []; |
||
426 | this.selected = _selected; |
||
427 | |||
428 | // Call the onExecute event of the first actionObject |
||
429 | for (var k in _links) |
||
430 | { |
||
431 | if (_links[k].visible) |
||
432 | { |
||
433 | hasLink = true; |
||
434 | |||
435 | // Only execute the following code if a JS function is registered |
||
436 | // for the action and this is the first action link |
||
437 | if (!this.helper && _links[k].actionObj.onExecute.hasHandler()) |
||
438 | { |
||
439 | this.helper = _links[k].actionObj.execute(_selected); |
||
440 | } |
||
441 | |||
442 | // Push the dragType of the associated action object onto the |
||
443 | // drag type list - this allows an element to support multiple |
||
444 | // drag/drop types. |
||
445 | var type = jQuery.isArray(_links[k].actionObj.dragType) ? _links[k].actionObj.dragType : [_links[k].actionObj.dragType]; |
||
446 | for(var i = 0; i < type.length; i++) |
||
447 | { |
||
448 | if (this.ddTypes.indexOf(type[i]) == -1) |
||
449 | { |
||
450 | this.ddTypes.push(type[i]); |
||
451 | } |
||
452 | } |
||
453 | } |
||
454 | } |
||
455 | |||
456 | // If no helper has been defined, create an default one |
||
457 | if (!this.helper && hasLink) |
||
458 | { |
||
459 | this.helper = ai.defaultDDHelper(_selected); |
||
460 | } |
||
461 | |||
462 | return true; |
||
463 | }; |
||
464 | |||
465 | return ai; |
||
466 | } |
||
467 | |||
724 |